package light3d;

public class FastMath 
{
	static Boolean isInit = false;
	final static int PRECISION = 4, MAX_INDEX = 360 << PRECISION, MULTIPLIER = 1 << PRECISION, HALF_INDEX = MAX_INDEX/2;
	 
	static double sinVal[] = new double[MAX_INDEX];
	static double cosVal[] = new double[MAX_INDEX];
	static double tanVal[] = new double[MAX_INDEX];
	public static void initTables()
	{
		if (isInit)
		{
			return;
		}
		isInit = true;
		 
		for (int i = 0; i < MAX_INDEX; i++)
		{
			sinVal[i] = Math.sin(FastMath.degreesToRadians((double)i * 360.0 / MAX_INDEX));
			cosVal[i] = Math.cos(FastMath.degreesToRadians((double)i * 360.0 / MAX_INDEX));
			tanVal[i] = Math.tan(FastMath.degreesToRadians((double)i * 360.0 / MAX_INDEX));
		}
	}
	/* POW 2 */
	public static int pow2(int x)
	{
		return x*x;
	}
	public static double pow2(double x)
	{
		return x*x;
	}
	/* SIN */
	public static double sin(int x)
	{
		x = FastMath.validateAngle(x);
		return sinVal[x << PRECISION];
	}
	public static double sin(double x)
	{
		x = FastMath.validateAngle(x);
		return sinVal[(int)(x * MULTIPLIER)];
	}
	/* COS */
	public static double cos(int x)
	{
		x = FastMath.validateAngle(x);
		return cosVal[x << PRECISION];
	}
	public static double cos(double x)
	{
		x = FastMath.validateAngle(x);
		return cosVal[(int)(x * MULTIPLIER)];
	}
	public static double tan(double x)
	{
		x = FastMath.validateAngle(x);
		return tanVal[(int)(x * MULTIPLIER)];
	}
	/* ATAN2 */
	public static double atan2(double y, double x)
	{
		return FastMath.radiansToDegrees(Math.atan2(y,x));
	}
	/* SQRT */
	public static double sqrt(double x)
	{
		return Math.sqrt(x);
	}
  public static double invSqrt(double x)
  {
    double xhalf = 0.5*x;
    int i = (int)x;
    i = 0x5f3759df - (i >> 1);
    x = (double)i;
    x = x*(1.5 - xhalf*x*x);
    return x;
  }
	public static double constrain(double x, double l, double h)
	{
		if (x < l)
		{
			return l;
		}
		if (x > h)
		{
			return h;
		}
		return x;
	}
	public static int validateAngle(int angle)
	{
		return (int)validateAngle((double)angle);
	}
	public static double validateAngle(double angle)
	{
		while (angle < 0)
		{
			angle += 360;
		}
		while (angle >= 360)
		{
			angle -= 360;
		}
		return angle;
	}
	//Used to convert between degrees and radians
	private static double degreesToRadians(double x)
	{
		return x / 180.0 * Math.PI;
	}
	@SuppressWarnings("unused")
	private static double radiansToDegrees(double x)
	{
		return x * 180.0 / Math.PI;
	}
}
